package de.velvettear.squirrel.gui;

import java.util.Vector;

import android.app.ActionBar;
import android.app.FragmentTransaction;
import android.app.ProgressDialog;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiManager;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.RadioButton;
import android.widget.TextView;
import android.widget.Toast;
import de.velvettear.squirrel.R;
import de.velvettear.squirrel.adapter.AccessPointAdapter;
import de.velvettear.squirrel.adapter.HostAdapter;
import de.velvettear.squirrel.adapter.PortAdapter;
import de.velvettear.squirrel.kernel.AccessPoint;
import de.velvettear.squirrel.kernel.Host;
import de.velvettear.squirrel.kernel.Ping;
import de.velvettear.squirrel.kernel.Port;
import de.velvettear.squirrel.kernel.Return;
import de.velvettear.squirrel.kernel.Statics;
import de.velvettear.squirrel.util.RootTools;
import de.velvettear.squirrel.util.WLANHelper;

public class NetworkFrame extends FragmentActivity implements ActionBar.TabListener {
		
	private static boolean IS_ROOTED = false;
	
	private static ViewPager viewPager;
	private SectionsPagerAdapter sectionsPagerAdapter;	
			
	// Ports-Fragment
	private static EditText ports_et_ip;
	private static EditText ports_et_range;

	// Ping-Fragment	
	private static EditText ping_et_ip;
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_networkframe);

		final ActionBar actionBar = getActionBar();
		actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);

		IS_ROOTED = RootTools.isRooted();
		
		sectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());

		viewPager = (ViewPager) findViewById(R.id.pager);
		viewPager.setAdapter(sectionsPagerAdapter);

		viewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
			@Override
			public void onPageSelected(int position) {
				actionBar.setSelectedNavigationItem(position);
			}
		});

		for (int i = 0; i < sectionsPagerAdapter.getCount(); i++) {
			actionBar.addTab(actionBar.newTab().setText(sectionsPagerAdapter.getPageTitle(i)).setTabListener(this));
		}
	}
	
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {						
		return super.onCreateOptionsMenu(menu);	
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		return super.onOptionsItemSelected(item);
	}
	
	@Override
	public void onTabSelected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
		invalidateOptionsMenu();
		viewPager.setCurrentItem(tab.getPosition());
	}

	@Override
	public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
		
	}

	@Override
	public void onTabReselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
		
	}
	
	public class SectionsPagerAdapter extends FragmentPagerAdapter {

		public SectionsPagerAdapter(FragmentManager fm) {
			super(fm);
		}

		@Override
		public Fragment getItem(int position) {
			switch (position) {
			
			case 0: return NetworkFragment.newInstance();
			case 1: return PortsFragment.newInstance();
			case 2: return AccessPointFragment.newInstance();
			case 3: return PingFragment.newInstance();
			
			default: return NetworkFragment.newInstance();
			
			}
		}

		@Override
		public int getCount() {	
			if (IS_ROOTED) {
				return 4;
			} else {
				return 3;
			}
		}

		@Override
		public CharSequence getPageTitle(int position) {
			switch (position) {
			case 0:
				return Statics.NETWORK;
			case 1:
				return Statics.PORTS;
			case 2:
				return Statics.ACCESS_POINTS;
			case 3:
				return Statics.PING;
			}
			return null;
		}
	}

	public static class NetworkFragment extends Fragment implements OnClickListener, OnItemClickListener {
		
		private HostAdapter hostAdapter;
		
		public NetworkFragment() {
			
		}

		public static NetworkFragment newInstance() {
			NetworkFragment fragment = new NetworkFragment();
			return fragment;
		}
		
		@Override
		public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
			View rootView = inflater.inflate(R.layout.fragment_network, container, false);
			
			final TextView tv_ip = (TextView) rootView.findViewById(R.id.network_tv_ip_value);
			final TextView tv_mac = (TextView) rootView.findViewById(R.id.network_tv_mac_value);
									
			Button btn_scan = (Button) rootView.findViewById(R.id.network_btn_scan);
			btn_scan.setOnClickListener(this);
						
			AsyncTask<Void, Void, Host> creation = new AsyncTask<Void, Void, Host>() {

				@Override
				protected Host doInBackground(Void... params) {					
					return WLANHelper.getLocalHost();
				}
				
				@Override
				protected void onPostExecute(Host localHost) {					
					tv_ip.setText(localHost.m_sIP);					
					tv_mac.setText(localHost.m_sMac);	
				}
				
			};
			creation.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);	
						
			return rootView;
		}

		@Override
		public void onClick(View v) {
			switch (v.getId()) {
			
			case R.id.network_btn_scan:
				startNetworkScan();				
				break;
			
			}			
		}	
			
		@Override
		public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
			String targetIP = hostAdapter.getItem(position).m_sIP;
			ports_et_ip.setText(targetIP);
			viewPager.setCurrentItem(1, true);
			
		}
		
		private void startNetworkScan() {
			final ProgressDialog progressDialog = new ProgressDialog(getActivity());
			progressDialog.setMessage("Netzwerk wird gescannt...");
			progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
			progressDialog.setMax(255);
			progressDialog.setProgress(0);
			progressDialog.setCanceledOnTouchOutside(false);
			progressDialog.setCancelable(false);
			progressDialog.show();
			
			AsyncTask<Void, Void, Return> networkScan = new AsyncTask<Void, Void, Return>() {

				@Override
				protected Return doInBackground(Void... params) {	
					Return ret = new Return();
					Vector<Host> hosts = new Vector<Host>();
					Host localHost = WLANHelper.getLocalHost();	
					for (int ip = 0; ip < 255; ip++) {
						Host targetHost = WLANHelper.tryToReach(localHost.m_sIP.substring(0, localHost.m_sIP.lastIndexOf(".") + 1) + ip);
						hosts.add(targetHost);						
						progressDialog.incrementProgressBy(1);
					}
					ret.m_bSuccess = true;
					ret.m_cDataList = hosts;					
					return ret;
				}
				
				@Override
				protected void onPostExecute(Return ret) {	
					if (ret.m_bSuccess) {
						fillHostList(ret.m_cDataList);
					}
					progressDialog.dismiss();	
				}
				
			};
			
			networkScan.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);	
		}
	
		private void fillHostList(Vector<Host> hosts) {
			LinearLayout ll_lv = (LinearLayout) getActivity().findViewById(R.id.network_ll_listview);
			ListView lv_hosts = (ListView) getActivity().findViewById(R.id.network_lv);			
			
			if (lv_hosts.getAdapter() != null) {
				lv_hosts.setAdapter(null);
			}
			
			hostAdapter = new HostAdapter(getActivity(), R.layout.listview_hosts, R.id.listview_ports_open, hosts);
			
			lv_hosts.setAdapter(hostAdapter);		
			lv_hosts.setOnItemClickListener(this);
			ll_lv.setVisibility(View.VISIBLE);
		}
						
	}

	public static class PortsFragment extends Fragment implements OnClickListener {
		
		private PortAdapter portAdapter;
		private Vector<Port> portList;		
		
		public PortsFragment() {
			
		}
 
		public static PortsFragment newInstance() {
			PortsFragment fragment = new PortsFragment();
			return fragment;
		}
		
		@Override
		public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
			View rootView = inflater.inflate(R.layout.fragment_ports, container, false);
						
			ports_et_ip = (EditText) rootView.findViewById(R.id.ports_et_ip);
			ports_et_range = (EditText) rootView.findViewById(R.id.ports_et_range);
			
			// Well-Known Ports als Default setzen
			ports_et_range.setText("1-1023");
			
			Button btn_scan = (Button) rootView.findViewById(R.id.ports_btn_scan);
			btn_scan.setOnClickListener(this);
			
			RadioButton rb_open = (RadioButton) rootView.findViewById(R.id.ports_rb_open);
			RadioButton rb_closed = (RadioButton) rootView.findViewById(R.id.ports_rb_closed);
			RadioButton rb_all = (RadioButton) rootView.findViewById(R.id.ports_rb_all);
			
			rb_open.setOnClickListener(this);
			rb_closed.setOnClickListener(this);
			rb_all.setOnClickListener(this);
			
			return rootView;
		}
		
		@Override
		public void onClick(View v) {
			switch (v.getId()) {
				
			case R.id.ports_btn_scan:
				startPortScan(true);
				break;
			
			case R.id.ports_rb_open:
				fillPortList(Statics.FILTER_OPEN);
				break;
				
			case R.id.ports_rb_closed:
				fillPortList(Statics.FILTER_CLOSED);
				break;
				
			case R.id.ports_rb_all:
				fillPortList(Statics.FILTER_ALL);
				break;
				
			}			
		}
		
		private boolean dataIsCorrect() {
			String msg = null;			
			if (ports_et_range.getText() == null || ports_et_range.getText().length() == 0) {
				msg = "Bitte tragen Sie die zu scannenden Ports ein!";			
			}
			if (ports_et_ip.getText() == null || ports_et_ip.getText().length() == 0) {
				msg = "Bitte tragen Sie eine IP-Adresse ein!";				
			}
			if (msg != null) {
				Toast.makeText(getActivity().getApplicationContext(), msg, Toast.LENGTH_SHORT).show();
				return false;
			}
								
			return true;
		}
		
		private Vector<String> getData() {
			// Daten aus Textfeldern holen			
			String targetRange = ports_et_range.getText().toString();
			targetRange = targetRange.replaceAll("[^\\d-]", "");
			if (targetRange.length() > 0) {
				String rangeStart;
				String rangeEnd;
				if (targetRange.contains("-")) {
					rangeStart = targetRange.split("-")[0];
					rangeEnd = targetRange.split("-")[1];							
				} else {
					rangeStart = targetRange;
					rangeEnd = targetRange;
				}		
				
				Vector<String> data = new Vector<String>();
				data.add(ports_et_ip.getText().toString());
				data.add(rangeStart);
				data.add(rangeEnd);
				return data;
			} else {
				return null;
			}
		}
		
		private void startPortScan() {
			startPortScan(false);
		}
		
		private void startPortScan(boolean networkExtern) {
			final boolean extern = networkExtern;
			if (dataIsCorrect()) {		
				Vector<String> data = getData();
				final ProgressDialog progressDialog = new ProgressDialog(getActivity());
				int rangeStart = Integer.parseInt(data.elementAt(1));
				int rangeEnd = Integer.parseInt(data.elementAt(2));
				int diff = (rangeEnd - rangeStart) + 1;
				progressDialog.setMessage("Scanne Ports ...");
				progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
				progressDialog.setMax(diff);
				progressDialog.setProgress(1);
				progressDialog.setCanceledOnTouchOutside(false);
				progressDialog.setCancelable(false);
				progressDialog.show();
				
				AsyncTask<String, Void, Return> portScan = new AsyncTask<String, Void, Return>() {

					@Override
					protected Return doInBackground(String... params) {		
						Return ret = new Return();
						String targetAddress = params[0];
						if (!extern && WLANHelper.tryToReach(targetAddress).m_bReachable) {
							int rangeStart = Integer.parseInt(params[1]);
							int rangeEnd = Integer.parseInt(params[2]);
							Vector<Port> ports = new Vector<Port>();
							for (int port = rangeStart; port < rangeEnd; port++) {
								Port targetPort = WLANHelper.scanPort(targetAddress, port);
								ports.add(targetPort);
								progressDialog.incrementProgressBy(1);
							}
							ret.m_bSuccess = true;
							ret.m_cDataList = ports;
						} else if (extern) {
							int rangeStart = Integer.parseInt(params[1]);
							int rangeEnd = Integer.parseInt(params[2]);
							Vector<Port> ports = new Vector<Port>();
							for (int port = rangeStart; port <= rangeEnd; port++) {
								Port targetPort = WLANHelper.scanPort(targetAddress, port);
								ports.add(targetPort);
								progressDialog.incrementProgressBy(1);
							}
							ret.m_bSuccess = true;
							ret.m_cDataList = ports;
						} else {
							ret.m_bSuccess = false;
							ret.m_sMessage = "Der Host " + targetAddress + " ist nicht erreichbar!";
						}
						return ret;
					}
					
					@Override
					protected void onPostExecute(Return ret) {	
						if (ret.m_bSuccess) {
							portList = ret.m_cDataList;
							fillPortList(Statics.FILTER_OPEN);
						} else {
							Toast.makeText(getActivity().getApplicationContext(), ret.m_sMessage, Toast.LENGTH_SHORT).show();
						}						
						progressDialog.dismiss();	
					}
					
				};				
				
				if (data != null) {
					portScan.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, data.elementAt(0), data.elementAt(1), data.elementAt(2));
				} else {
					Toast.makeText(getActivity().getApplicationContext(), "IP oder Portrange fehlerhaft angegeben!", Toast.LENGTH_SHORT).show();
				}
			} 		
		}
		
		private void fillPortList(String filter) {
			// Liste filtern
			Vector<Port> ports = new Vector<Port>();
			if (filter.equals(Statics.FILTER_OPEN)) {
				for (Port p : portList) {
					if (p.m_bOpen) {
						ports.add(p);
					}
				}
			} else if (filter.equals(Statics.FILTER_CLOSED)) {
				for (Port p : portList) {
					if (!p.m_bOpen) {
						ports.add(p);
					}
				}
			} else if (filter.equals(Statics.FILTER_ALL)) {
				ports = portList;
			}
			
			LinearLayout ll_lv = (LinearLayout) getActivity().findViewById(R.id.ports_ll_listview);
			ListView lv_ports = (ListView) getActivity().findViewById(R.id.ports_lv);				
			
			if (lv_ports.getAdapter() != null) {
				lv_ports.setAdapter(null);
			}
			
			portAdapter = new PortAdapter(getActivity(), R.layout.listview_ports, R.id.listview_ports_number, ports);
			
			lv_ports.setAdapter(portAdapter);		
			ll_lv.setVisibility(View.VISIBLE);
		}		
		
	}
			
	public static class AccessPointFragment extends Fragment implements OnItemClickListener {
		
		private AccessPointAdapter accessPointAdapter;
		private AccessPointReceiver apReceiver;
		private Vector<AccessPoint> accessPointList;
		
		private LinearLayout ll_lv;
		private LinearLayout ll_search;
		
		public AccessPointFragment() {
			
		}

		public static AccessPointFragment newInstance() {
			AccessPointFragment fragment = new AccessPointFragment();
			return fragment;
		}
		
		@Override
		public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
			View rootView = inflater.inflate(R.layout.fragment_accesspoints, container, false);
								
			return rootView;
		}
		
		@Override 
		public void onResume() {
			super.onResume();
			ll_search = (LinearLayout) getActivity().findViewById(R.id.accesspoints_ll_search);
			ll_search.setVisibility(View.VISIBLE);
			
			ll_lv = (LinearLayout) getActivity().findViewById(R.id.accesspoints_ll_listview);
			ll_lv.setVisibility(View.GONE);
			
			apReceiver = new AccessPointReceiver();
			getActivity().registerReceiver(apReceiver, new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));
			WLANHelper.wifiManager.startScan();
		}
		
		@Override
		public void onPause() {
			super.onPause();
			
			getActivity().unregisterReceiver(apReceiver);
		}
		
		@Override
		public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
			Intent bruteForceIntent = new Intent(getActivity().getApplicationContext(), BruteForce.class);
			bruteForceIntent.putExtra(Statics.INTENT_BRUTEFORCE, accessPointList.elementAt(position).m_sSSID);
			startActivity(bruteForceIntent);			
		}
		
		private void fillAccessPointList() {					
			ListView lv_aps = (ListView) getActivity().findViewById(R.id.accesspoints_lv);				
			
			if (lv_aps.getAdapter() != null) {
				lv_aps.setAdapter(null);
			}
			
			accessPointAdapter = new AccessPointAdapter(getActivity(), R.layout.listview_accesspoints, R.id.listview_accesspoints_ssid, accessPointList);
			
			lv_aps.setAdapter(accessPointAdapter);		
			lv_aps.setOnItemClickListener(this);
			ll_search.setVisibility(View.GONE);
			ll_lv.setVisibility(View.VISIBLE);
		}		
		
		public class AccessPointReceiver extends BroadcastReceiver {
						
			public void onReceive(Context c, Intent intent) {
				accessPointList = new Vector<AccessPoint>();
				for (ScanResult result : WLANHelper.wifiManager.getScanResults()) {
					AccessPoint ap = new AccessPoint();
					ap.m_sBSSID = result.BSSID;
					ap.m_sCapabilities = result.capabilities;
					ap.m_sSSID = result.SSID;
					ap.m_nFrequency = result.frequency;
					ap.m_nLevel = result.level;
					accessPointList.add(ap);
				}
								
				fillAccessPointList();
			}
		}
		
	}
	
	public static class PingFragment extends Fragment implements OnClickListener {
		
		public PingFragment() {
			
		}

		public static PingFragment newInstance() {
			PingFragment fragment = new PingFragment();
			return fragment;
		}
		
		@Override
		public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
			View rootView = inflater.inflate(R.layout.fragment_ping, container, false);
					
			ping_et_ip = (EditText) rootView.findViewById(R.id.ping_et_ip);
			
			Button btn_execute = (Button) rootView.findViewById(R.id.ping_btn_execute);
			btn_execute.setOnClickListener(this);
			
			return rootView;
		}

		@Override
		public void onClick(View v) {
			switch (v.getId()) {
				
			case R.id.ping_btn_execute:
				executePing();
				break;
			
			}			
		}
					
		private void executePing() {			
			AsyncTask<Void, Void, Return> ping = new AsyncTask<Void, Void, Return>() {

				@Override
				protected Return doInBackground(Void... params) {
					Ping p = WLANHelper.ping(ping_et_ip.getText().toString());
					return null;
				}
				
				@Override
				protected void onPostExecute(Return ret) {	
					if (ret.m_bSuccess) {
						
					} else {
						Toast.makeText(getActivity().getApplicationContext(), ret.m_sMessage, Toast.LENGTH_SHORT).show();
					}							
				}
				
			};
			
			ping.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
			
		}
		
	}
	
}
